<template>
    <div ref="chartContainer" :style="{
        width: '100%',
        height: computedHeight + 'px',
        maxHeight: maxHeight ? maxHeight + 'px' : undefined,
        overflowY: 'auto'
    }"></div>
</template>

<script>
import * as d3 from 'd3';
import { min } from 'd3';
import { th } from 'element-plus/es/locales.mjs';

const minNodeGap = 50;
const minHeight = 200;

export default {
    props: ['nodes', 'links', 'maxHeight', 'showHoverPolicyWindow'],
    data() {
        return {
            hoveredNodeId: null,
            dynamicHeight: minHeight,
        };
    },
    computed: {
        computedHeight() {
            return this.dynamicHeight;
        }
    },
    mounted() {
        this.drawChart();
        window.addEventListener('resize', this.drawChart);

        this._resizeObserver = new ResizeObserver(() => this.drawChart());
        this._resizeObserver.observe(this.$refs.chartContainer);
    },
    beforeUnmount() {
        window.removeEventListener('resize', this.drawChart);
        this._resizeObserver.disconnect();
    },
    watch: {
        nodes: { handler: 'drawChart', deep: true },
        links: { handler: 'drawChart', deep: true }
    },
    methods: {
        handleNodeClick(id) {
            console.log('Node clicked:', id);
            this.$emit('node-click', id);
        },
        drawChart() {
            const relatedNodeIds = new Set();
            if (this.hoveredNodeId) {
                relatedNodeIds.add(this.hoveredNodeId);
                this.links.forEach(link => {
                    if (link.source === this.hoveredNodeId) relatedNodeIds.add(link.target);
                    if (link.target === this.hoveredNodeId) relatedNodeIds.add(link.source);
                });
            }

            const container = this.$refs.chartContainer;
            const width = container.clientWidth;
            const height = this.dynamicHeight;
            if (!width || !height) {
                setTimeout(this.drawChart, 100);
                return;
            }

            d3.select(container).selectAll('*').remove();
            const svg = d3.select(container).append('svg')
                .attr('width', width)
                .attr('height', height);


            svg.insert('rect', ':first-child')
                .attr('width', width)
                .attr('height', height)
                .attr('fill', 'transparent')  // 透明但可接收事件
                .on('mousemove', () => {
                    if (this.hoveredNodeId) {
                        this.hoveredNodeId = null;
                        this.$emit('node-hover', null);
                    }
                    this.$nextTick(() => {
                        this.drawChart(); // 重新绘制图表以清除高亮状态
                    });
                });
            ;

            const years = [...new Set(this.nodes.map(n => new Date(n.publish_date).getFullYear()))].sort();
            const horizontalPadding = 50;
            const xScale = d3.scalePoint()
                .domain(years)
                .range([horizontalPadding, width - horizontalPadding])
                .padding(0.5);

            // group nodes by year and sort by time
            const nodesByYear = {};
            this.nodes.forEach(n => {
                const year = new Date(n.publish_date).getFullYear();
                if (!nodesByYear[year]) nodesByYear[year] = [];
                nodesByYear[year].push(n);
            });

            Object.keys(nodesByYear).forEach(year => {
                nodesByYear[year].sort((a, b) => new Date(a.publish_date) - new Date(b.publish_date));
            });
            // 获取每个年份（x轴列）的节点数量
            const maxCount = Math.max(...Object.values(nodesByYear).map(group => group.length));
            this.dynamicHeight = Math.max(minHeight, 100 + maxCount * minNodeGap + 150);


            const nodePositions = {};
            const yStart = 80;
            Object.entries(nodesByYear).forEach(([year, group]) => {
                const x = xScale(+year);
                group.forEach((n, i) => {
                    nodePositions[n.id] = {
                        x,
                        y: yStart + i * minNodeGap
                    };
                });
            });

            const defs = svg.append('defs');

            defs.append('marker')
                .attr('id', 'arrow')
                .attr('viewBox', '0 -5 10 10')
                .attr('refX', 10) // 控制箭头离路径末端的距离
                .attr('refY', 0)
                .attr('markerWidth', 6)
                .attr('markerHeight', 6)
                .attr('orient', 'auto')
                .attr('markerUnits', 'strokeWidth')
                .append('path')
                .attr('d', 'M0,-5L10,0L0,5')  // 三角箭头
                .attr('fill', '#66ccff'); // 箭头颜色

            defs.append('marker')
                .attr('id', 'arrow-highlight')
                .attr('viewBox', '0 -5 10 10')
                .attr('refX', 10)
                .attr('refY', 0)
                .attr('markerWidth', 6)
                .attr('markerHeight', 6)
                .attr('orient', 'auto')
                .attr('markerUnits', 'strokeWidth')
                .append('path')
                .attr('d', 'M0,-5L10,0L0,5')
                .attr('fill', '#34d399');




            // draw curved links
            this.links.forEach(link => {
                const s = nodePositions[link.source];
                const t = nodePositions[link.target];
                if (!s || !t) return;

                const targetNode = this.nodes.find(n => n.id === link.target);
                const r = targetNode?.isCenter ? 24 : 12;

                const dx = t.x - s.x;
                const dy = t.y - s.y;
                const len = Math.sqrt(dx * dx + dy * dy);
                const tx = t.x - (dx / len) * r;
                const ty = t.y - (dy / len) * r;

                const midX = (s.x + tx) / 2;
                const isHighlight = this.hoveredNodeId && (link.source === this.hoveredNodeId || link.target === this.hoveredNodeId);

                const shouldShowLink = !this.hoveredNodeId ||
                    (relatedNodeIds.has(link.source) && relatedNodeIds.has(link.target));

                if (!shouldShowLink) return;

                const path = d3.path();
                path.moveTo(s.x, s.y);
                path.quadraticCurveTo(midX, Math.min(s.y, ty) - 40, tx, ty);

                svg.append('path')
                    .attr('d', path.toString())
                    .attr('stroke', isHighlight ? '#34d399' : '#66ccff')
                    .attr('stroke-width', isHighlight ? 2 : 1)
                    .attr('fill', 'none')
                    .attr('opacity', isHighlight ? 1 : 0.5)
                    .attr('marker-end', isHighlight ? 'url(#arrow-highlight)' : 'url(#arrow)');
            });

            // draw nodes
            const nodeGroup = svg.selectAll('.node')
                .data(this.nodes)
                .enter()
                .append('g')
                .attr('class', 'node')
                .attr('transform', d => {
                    const p = nodePositions[d.id];
                    return `translate(${p.x},${p.y})`;
                })
                .style('cursor', 'pointer')
                .on('mouseenter', (event, d) => {
                    this.hoveredNodeId = d.id;

                    const containerRect = this.$refs.chartContainer.getBoundingClientRect();
                    const nodeRect = event.currentTarget.getBoundingClientRect();
                    const x = nodeRect.left + nodeRect.width / 2 - containerRect.left;
                    const y = nodeRect.top - containerRect.top;

                    this.$emit('node-hover', {
                        node: d,
                        x,
                        y
                    });
                    this.$nextTick(() => {
                        this.drawChart(); // 重新绘制图表以更新高亮状态
                    });
                })
                .on('mouseleave', () => {
                    this.hoveredNodeId = null;
                    this.$emit('node-hover', null);
                    this.$nextTick(() => {
                        this.drawChart(); // 重新绘制图表以清除高亮状态
                    });
                })

                .on('click', (event, d) => {
                    console.log('Node clicked:', d.id);
                    event.stopPropagation(); // 停止冒泡
                    this.handleNodeClick(d.id);
                });

            nodeGroup.append('circle')
                .attr('r', d => d.isCenter ? 24 : 12)
                .attr('fill', d => {
                    if (this.hoveredNodeId && relatedNodeIds.has(d.id)) {
                        return '#34d399'; // 高亮色
                    }
                    return d.isCenter ? '#38bdf8' : '#66ccff';
                })
                .attr('opacity', d => {
                    if (!this.hoveredNodeId) return 1;
                    return relatedNodeIds.has(d.id) ? 1 : 0.2;
                });



            nodeGroup.append('text')
                .attr('y', 28)
                .attr('text-anchor', 'middle')
                .attr('fill', '#66ccff')
                .attr('font-size', 9)
                .attr('opacity', d => {
                    if (!this.hoveredNodeId) return 1;
                    return relatedNodeIds.has(d.id) ? 1 : 0.2;
                })
                .text(d => d.publish_date ? d.publish_date.slice(0, 10) : '');

            // 如果不展示政策之窗，就直接在图上展示文本
            if (!this.showHoverPolicyWindow && this.hoveredNodeId) {
                const hoveredNode = this.nodes.find(n => n.id === this.hoveredNodeId);
                const pos = nodePositions[this.hoveredNodeId];
                if (hoveredNode && pos) {
                    svg.append('text')
                        .attr('x', pos.x)
                        .attr('y', pos.y - (hoveredNode.isCenter ? 30 : 24)) // 节点上方显示
                        .attr('text-anchor', 'middle')
                        .attr('fill', '#fff')
                        .attr('font-size', 12)
                        .attr('pointer-events', 'none') // 不干扰鼠标事件
                        .text(hoveredNode.title);
                }
            }



            // axis
            const xAxis = d3.axisBottom(xScale);
            svg.append('g')
                .attr('transform', `translate(0, ${height - 30})`)
                .call(xAxis)
                .selectAll('text')
                .attr('fill', '#aaa');

            // legend
            const legend = svg.append('g')
                .attr('transform', 'translate(16,16)');
            legend.append('circle')
                .attr('cx', 0)
                .attr('cy', 0)
                .attr('r', 8)
                .attr('fill', '#38bdf8');
            legend.append('text')
                .attr('x', 16)
                .attr('y', 4)
                .attr('fill', '#66ccff')
                .attr('font-size', 12)
                .text('本条政策');

        }
    }
};
</script>

<style scoped>
.node:hover circle {
    fill: #0ff;
    stroke-width: 3;
}
</style>
